
/* List all the "API" functions. */

// Finds the portions between commas in a series
// (ignoring commas in properly nested functions).
// DEBUG: blurt = true to print simultaneously.
vector<string>& find_all_columns( const string& s, const bool& blurt = false ){
	vector<string> *extracted = new vector<string>;
	int count = 0, last = 0, end = s.length()-1;
	char current;
	for( int i = 0, l = s.length(); i < l; i++ ){
		current = s.at( i );
		if( current == '(' or current == '{' ) count++;
		else if( current == ')' or current == '}' ) count--;
		if( count == 0 ){
			if( current == ',' ){
				if( blurt ) cout << "## " << s.substr( last, i-last ) << endl;
				extracted->push_back( s.substr( last, i-last ) );
				last = i+1;
			}
			else if( i == end ){
				if( blurt ) cout << "## " << s.substr( last, i-last+1 ) << endl;
				extracted->push_back( s.substr( last, i-last+1 ) );
			}
		}
	}
	return *extracted;
}

// Global replace (without any RegEx) - that's it.
void replace_all_linearly( string& s, const string& match,
		const string& replacement ){
	if( s.empty() or match.empty() )
		return;
	for(
		size_t pos = 0;
		( pos = s.find( match, pos ) ) != string::npos;
		pos += replacement.length()
	)
		s.replace( pos, match.length(), replacement );
}

// Takes care of special characters inside an
// "ordinary" string to be searched (to avoid
// them to be mistaken for RegEx syntax)!
vector<string> special{ "\\", "[", "^", "$", ".", "|",
		"?", "*", "+", "(", ")", "{", "}" };
string& regex_compatible( const string& s ){
	string *res = new string;
	*res = s;
	for( unsigned i = 0; i < 13; i++ )
		replace_all_linearly( *res, special[ i ], special[0]+special[ i ] );
	return *res;
}

// DEBUG: blurt = true to print simultaneously.
vector<string>& process_all_columns( const string& s,
		const bool& blurt = false, const bool& force = false ){
	string current, regexp, remnant = s;
	vector<string> *result = new vector<string>;
	*result = find_all_columns( s );
	for( unsigned i = 0; i < result->size(); i++ ){
		current = result->at( i );
		regexp = regex_compatible( current );
		if( RE( "^"+regexp+"(,|$)" ).PartialMatch( remnant ) ){
			replace_first( remnant, current, "" );
			replace_first( remnant, ",", "" );
		}
		trim( result->at( i ) );
		current = result->at( i );
		if( !current.empty() ){ if( blurt ) cout << "## " << current << endl; }
		else{ result->erase( result->begin() + ( i-- ) ); }
	}
	if( force or !remnant.empty() ){
		if( blurt ) cout << endl << "#! " << remnant << endl;
		result->push_back( "#! " + remnant );
	}
	return *result;
}

// Quick function to print a vector of strings, where separator
// can be any string to be printed "between" two elements of v
// (and at the end too)!
void blurt( const vector<string>& v, const bool& error = false,
		const string& separator = "\n" ){
	if( error ){
		for( int i = 0, l = v.size(); i < l; i++ )
			cerr << v.at( i ) << separator;
		cerr << endl;
	}
	else{
		for( int i = 0, l = v.size(); i < l; i++ )
			cout << v.at( i ) << separator;
	}
}

// By default, with processed = true, empty (including whitespace only)
// "instances" between commas are ignored. Also, remnant must not exist.
// If false, both these checks are not enforced (useful when the exact
// "position" of the column+ [or whatever/table!] name is known).
pair<bool,string> nth_column( const unsigned& n,
		const string& s, const bool& processed = true ){

	bool valid = false;
	string value = blank;

	vector<string> verify_entire;
	unsigned count;
	if( processed ){
		verify_entire = process_all_columns( s, false, true );
		count = verify_entire.size()-1;
	}
	else{
		verify_entire = find_all_columns( s );
		count = verify_entire.size();
	}

	unsigned n_wrap = n;
	if( n == 0 ) n_wrap = count;

	if( count > 0 )
		if( n_wrap <= count ){
			if( processed ) value = verify_entire.at( count );
			else value = verify_entire.at( count-1 );
			if( value.substr( 0, 3 ) != string( "#! " )
					or value == string( "#! " ) ){
				value = verify_entire.at( n_wrap-1 );
				valid = true;
			}
			else value = blank;
		}

	return make_pair( valid, value );

}

pair<bool,string> first( const string& s, const bool& processed = false ){
	return nth_column( 1, s, processed );
}

pair<bool,string> last( const string& s, const bool& processed = false ){
	return nth_column( 0, s, processed );
}
